package org.exhaust.framework.net.common.protocol;

import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Collectors;

@Slf4j
public class ChannelEventDispatcher implements ChannelEventHandler {

    private final Collection<ChannelEventHandler> channelHandlers = new CopyOnWriteArraySet<>();

    public ChannelEventDispatcher(ChannelEventHandler... handlers) {
        if (handlers != null) {
            this.channelHandlers.addAll(Arrays.asList(handlers).stream().filter(Objects::nonNull).collect(Collectors.toSet()));
        }
    }

    public ChannelEventDispatcher addChannelHandler(ChannelEventHandler handler) {
        this.channelHandlers.add(handler);
        return this;
    }

    public ChannelEventDispatcher removeChannelHandler(ChannelEventHandler handler) {
        this.channelHandlers.remove(handler);
        return this;
    }

    @Override
    public void channelActive(Channel channel) {
        for (ChannelEventHandler listener : channelHandlers) {
            try {
                listener.channelActive(channel);
            } catch (Throwable t) {
                log.error(t.getMessage(), t);
            }
        }
    }

    @Override
    public void channelInActive(Channel channel) {
        for (ChannelEventHandler listener : channelHandlers) {
            try {
                listener.channelInActive(channel);
            } catch (Throwable t) {
                log.error(t.getMessage(), t);
            }
        }
    }

    @Override
    public void channelRegistered(Channel channel) {
        for (ChannelEventHandler listener : channelHandlers) {
            try {
                listener.channelRegistered(channel);
            } catch (Throwable t) {
                log.error(t.getMessage(), t);
            }
        }
    }

    @Override
    public void channelUnRegistered(Channel channel) {
        for (ChannelEventHandler listener : channelHandlers) {
            try {
                listener.channelUnRegistered(channel);
            } catch (Throwable t) {
                log.error(t.getMessage(), t);
            }
        }
    }

    @Override
    public void channelReaderIdle(Channel channel) {
        for (ChannelEventHandler listener : channelHandlers) {
            try {
                listener.channelReaderIdle(channel);
            } catch (Throwable t) {
                log.error(t.getMessage(), t);
            }
        }
    }

    @Override
    public void channelWriterIdle(Channel channel) {
        for (ChannelEventHandler listener : channelHandlers) {
            try {
                listener.channelWriterIdle(channel);
            } catch (Throwable t) {
                log.error(t.getMessage(), t);
            }
        }
    }

    @Override
    public void exceptionCaught(Channel channel, Throwable throwable) {
        for (ChannelEventHandler listener : channelHandlers) {
            try {
                listener.exceptionCaught(channel, throwable);
            } catch (Throwable t) {
                log.error(t.getMessage(), t);
            }
        }
    }
}
